import argparse
import sys
from pathlib import Path

from PIL import Image


def write_pixels(prefix, fn, invert=False):
    img = Image.open(fn).convert(mode="RGB")
    out = [
        f"const glyph_t {prefix}{fn.stem} = {{\n",
        f"    .height = {img.height},\n",
        f"    .width = {img.width},\n",
        "    .data = {\n",
    ]
    header = f"extern const glyph_t {prefix}{fn.stem};\n"

    for y in range(img.height):
        bits_data = 0
        bits_count = 0

        hex_data = ["        "]
        comment_graphic = [
            " // ",
        ]

        for x in range(img.width):
            pixel = img.getpixel((x, y))
            pixel = sum(pixel) / len(pixel)

            if invert:
                if pixel < 127:
                    bits_data |= 1 << (7 - bits_count)
                    comment_graphic.append("#")
                else:
                    comment_graphic.append(" ")
            else:
                if pixel > 127:
                    bits_data |= 1 << (7 - bits_count)
                    comment_graphic.append("#")
                else:
                    comment_graphic.append(" ")

            bits_count += 1

            if bits_count == 8:
                hex_data.append(f"0x{bits_data:02X}, ")
                bits_data, bits_count = 0, 0

        if bits_count:
            hex_data.append(f"0x{bits_data:02X}, ")
            bits_data, bits_count = 0, 0

        out.extend(hex_data)
        out.append("".join(comment_graphic).rstrip())
        out.append("\n")

    out.append("    }\n")
    out.append("};\n")
    return "".join(out), header


def main():
    parser = argparse.ArgumentParser()
    parser.add_argument("dir", type=Path)
    parser.add_argument("--output-c", type=Path, default="Core/Src/segments.c")
    parser.add_argument("--output-h", type=Path, default="Core/Inc/segments.h")
    parser.add_argument("--prefix", default="img_")
    parser.add_argument("--invert", action="store_true")
    args = parser.parse_args()

    output_cs = [
        "// Do not directly modify.\n",
        f"// Generated by {' '.join(sys.argv)}\n",
        '#include "segments.h"\n',
        "\n",
    ]
    output_hs = [
        "#pragma once\n// Do not directly modify.\n",
        f"// Generated by {' '.join(sys.argv)}\n",
        "\n",
        "#include <stdint.h>\n",
        "\n",
        "typedef struct {\n",
        "    uint16_t width;\n",
        "    uint16_t height;\n",
        "    const char data[];\n",
        "} glyph_t;\n",
        "\n",
    ]
    for fn in sorted(args.dir.glob("*.png")):
        output_cs.append("\n")
        c, h = write_pixels(args.prefix, fn, invert=args.invert)
        output_cs.append(c)
        output_hs.append(h)
    args.output_c.write_text("".join(output_cs))
    args.output_h.write_text("".join(output_hs))


if __name__ == "__main__":
    main()
